package main

import (
	"fmt"
	"math"
)

// 定义一个简单的接口
type Shape interface {
	Area() float64
	Perimeter() float64
}

// 定义另一个接口
type Object interface {
	Volume() float64
}

// 定义一个组合接口
type Material interface {
	Shape
	Object
	Density() float64
}

// 实现Shape接口的结构体
type Rectangle struct {
	Width, Height float64
}

func (r Rectangle) Area() float64 {
	return r.Width * r.Height
}

func (r Rectangle) Perimeter() float64 {
	return 2 * (r.Width + r.Height)
}

// 实现Shape接口的另一个结构体
type Circle struct {
	Radius float64
}

func (c Circle) Area() float64 {
	return math.Pi * c.Radius * c.Radius
}

func (c Circle) Perimeter() float64 {
	return 2 * math.Pi * c.Radius
}

// 实现Material接口的结构体
type Cube struct {
	Side    float64
	density float64
}

func (c Cube) Area() float64 {
	return 6 * math.Pow(c.Side, 2)
}

func (c Cube) Perimeter() float64 {
	return 12 * c.Side
}

func (c Cube) Volume() float64 {
	return math.Pow(c.Side, 3)
}

func (c Cube) Density() float64 {
	return c.density
}

// 空接口
type Any interface{}

func main() {
	fmt.Println("11. 接口")

	// 接口的基本使用
	fmt.Println("\n--- 接口的基本使用 ---")

	// 创建实现接口的结构体实例
	rect := Rectangle{Width: 10, Height: 5}
	circle := Circle{Radius: 3}

	// 通过接口变量调用方法
	var shape Shape
	shape = rect
	fmt.Printf("矩形面积: %.2f, 周长: %.2f\n", shape.Area(), shape.Perimeter())

	shape = circle
	fmt.Printf("圆形面积: %.2f, 周长: %.2f\n", shape.Area(), shape.Perimeter())

	// 接口切片
	fmt.Println("\n--- 接口切片 ---")
	shapes := []Shape{
		Rectangle{Width: 4, Height: 3},
		Circle{Radius: 2},
		Rectangle{Width: 5, Height: 6},
	}

	for _, s := range shapes {
		fmt.Printf("面积: %.2f, 周长: %.2f\n", s.Area(), s.Perimeter())
	}

	// 接口类型断言
	fmt.Println("\n--- 接口类型断言 ---")
	var obj Shape = Rectangle{Width: 2, Height: 3}

	// 类型断言
	if rect, ok := obj.(Rectangle); ok {
		fmt.Printf("类型断言成功: Rectangle{Width: %.2f, Height: %.2f}\n", rect.Width, rect.Height)
	}

	// 类型断言失败的情况
	if circle, ok := obj.(Circle); ok {
		fmt.Printf("这是圆形，半径: %.2f\n", circle.Radius)
	} else {
		fmt.Println("这不是圆形")
	}

	// 类型切换
	fmt.Println("\n--- 类型切换 ---")
	printShapeDetails := func(s Shape) {
		switch shape := s.(type) {
		case Rectangle:
			fmt.Printf("矩形: 宽=%.2f, 高=%.2f, 面积=%.2f\n", shape.Width, shape.Height, shape.Area())
		case Circle:
			fmt.Printf("圆形: 半径=%.2f, 面积=%.2f\n", shape.Radius, shape.Area())
		default:
			fmt.Println("未知形状")
		}
	}

	printShapeDetails(rect)
	printShapeDetails(circle)

	// 空接口的使用
	fmt.Println("\n--- 空接口 ---")
	var any Any

	any = 42
	fmt.Printf("any = %v, 类型: %T\n", any, any)

	any = "Hello"
	fmt.Printf("any = %v, 类型: %T\n", any, any)

	any = true
	fmt.Printf("any = %v, 类型: %T\n", any, any)

	any = Rectangle{Width: 1, Height: 2}
	fmt.Printf("any = %v, 类型: %T\n", any, any)

	// 空接口切片可以存储任何类型
	mixedSlice := []Any{42, "Hello", true, Rectangle{Width: 1, Height: 2}}
	for _, v := range mixedSlice {
		fmt.Printf("值: %v, 类型: %T\n", v, v)
	}

	// 组合接口的使用
	fmt.Println("\n--- 组合接口 ---")
	var material Material = Cube{Side: 3, density: 2.5}
	fmt.Printf("立方体表面积: %.2f\n", material.Area())
	fmt.Printf("立方体周长: %.2f\n", material.Perimeter())
	fmt.Printf("立方体体积: %.2f\n", material.Volume())
	fmt.Printf("立方体密度: %.2f\n", material.Density())

	// 接口的零值
	fmt.Println("\n--- 接口的零值 ---")
	var s Shape
	fmt.Printf("接口零值: %v, 是否为nil: %t\n", s, s == nil)

	// 接口与指针
	fmt.Println("\n--- 接口与指针 ---")
	rectPtr := &Rectangle{Width: 5, Height: 4}
	var shapePtr Shape = rectPtr
	fmt.Printf("指针实现接口 - 面积: %.2f\n", shapePtr.Area())

	// 接口相等性比较
	fmt.Println("\n--- 接口相等性比较 ---")
	var s1, s2 Shape
	fmt.Printf("两个nil接口是否相等: %t\n", s1 == s2)

	s1 = Rectangle{Width: 1, Height: 1}
	s2 = Rectangle{Width: 1, Height: 1}
	fmt.Printf("两个相同值的接口是否相等: %t\n", s1 == s2)

	// 接口在函数中的应用
	fmt.Println("\n--- 接口在函数中的应用 ---")
	printArea(rect)
	printArea(circle)

	// 接口作为函数返回值
	fmt.Println("\n--- 接口作为函数返回值 ---")
	shapeFactory := func(shapeType string) Shape {
		switch shapeType {
		case "rectangle":
			return Rectangle{Width: 2, Height: 3}
		case "circle":
			return Circle{Radius: 2}
		default:
			return nil
		}
	}

	newRect := shapeFactory("rectangle")
	newCircle := shapeFactory("circle")

	fmt.Printf("工厂创建的矩形面积: %.2f\n", newRect.Area())
	fmt.Printf("工厂创建的圆形面积: %.2f\n", newCircle.Area())
}

// 接口作为函数参数
func printArea(s Shape) {
	fmt.Printf("形状的面积是: %.2f\n", s.Area())
}
